package financial.mock;

import net.datafaker.Faker;

import java.io.BufferedWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

public class CsvDataGenerator {
    private static final Faker faker = new Faker(new Locale("zh-CN"));
    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern(Config.DATE_FORMAT);
    private static final DateTimeFormatter TIMESTAMP_FORMAT = DateTimeFormatter.ofPattern(Config.DATE_TIME_FORMAT);
    private static final String DT = "20250701";  // COB日期分区值
    private static final int TOTAL_RECORDS = 1_000_0;
    private static final int BATCH_SIZE = 10_000;

    public static void main(String[] args) throws Exception {
        // 生成基础参考数据
        generateReferenceData();

        // 生成客户数据并保存ID
        List<String> customerIds = generateCustomerData();

        // 生成账户数据并保存账号
        List<String> accountNumbers = generateAccountData(customerIds);

        // 生成交易数据
        generateTransactionData(accountNumbers);

        // 生成日志数据
        generateLogData();
    }

    // 生成交易参考表（小数据量）
    private static void generateReferenceData() throws Exception {
        try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(Config.CSV_PATH+"transaction_reference.csv"))) {
            writer.write("transaction_code,description,category,dt\n");
            String[][] referenceData = {
                    {"T001", "转账", "支出", DT},
                    {"T002", "消费", "支出", DT},
                    {"T003", "存款", "收入", DT},
                    {"T004", "工资", "收入", DT},
                    {"T005", "退款", "收入", DT}
            };
            for (String[] data : referenceData) {
                writer.write(String.join(",", data) + "\n");
            }
        }
    }

    // 生成客户信息表
    private static List<String> generateCustomerData() throws Exception {
        List<String> customerIds = new ArrayList<>(TOTAL_RECORDS);
        try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(Config.CSV_PATH+"customer_info.csv"))) {
            writer.write("customer_id,name,id_card_no,phone,address,create_time,update_time,dt\n");

            for (int i = 0; i < TOTAL_RECORDS; i++) {
                String[] customer = {
                        UUID.randomUUID().toString(),
                        faker.name().fullName(),
                        generateValidIdCard(),
                        faker.phoneNumber().cellPhone(),
                        faker.address().fullAddress(),
                        faker.timeAndDate().past(365, TimeUnit.DAYS, Config.DATE_TIME_FORMAT),
                        faker.timeAndDate().past(30, TimeUnit.DAYS, Config.DATE_TIME_FORMAT),
                        DT
                };
                customerIds.add(customer[0]);
                writer.write(String.join(",", customer) + "\n");

                if (i % BATCH_SIZE == 0) writer.flush();
            }
        }
        return customerIds;
    }

    // 生成账户信息表
    private static List<String> generateAccountData(List<String> customerIds) throws Exception {
        List<String> accountNumbers = new ArrayList<>(TOTAL_RECORDS);
        try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(Config.CSV_PATH+"account_info.csv"))) {
            writer.write("account_no,customer_id,account_type,balance,open_date,status,last_updated_time,dt\n");

            for (int i = 0; i < TOTAL_RECORDS; i++) {
                String customerId = customerIds.get(i);
                String[] account = {
                        "ACCT" + System.nanoTime() + ThreadLocalRandom.current().nextInt(1000, 9999),
                        customerId,
                        faker.options().option("储蓄账户", "对公账户"),
                        String.format("%.2f", faker.number().randomDouble(2, 1000, 1000000)),
                        faker.timeAndDate().past(365, TimeUnit.DAYS, Config.DATE_FORMAT),
                        faker.options().option("正常", "冻结"),
                        faker.timeAndDate().past(30, TimeUnit.DAYS, Config.DATE_TIME_FORMAT),
                        DT
                };
                accountNumbers.add(account[0]);
                writer.write(String.join(",", account) + "\n");

                if (i % BATCH_SIZE == 0) writer.flush();
            }
        }
        return accountNumbers;
    }

    // 生成交易流水表
    private static void generateTransactionData(List<String> accountNumbers) throws Exception {
        String[] transCodes = {"T001", "T002", "T003", "T004", "T005"};
        try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(Config.CSV_PATH+"transaction_flow.csv"))) {
            writer.write("transaction_id,account_no,transaction_code,amount,currency,counterparty_account," +
                    "transaction_time,status,channel,dt\n");

            for (int i = 0; i < TOTAL_RECORDS; i++) {
                String accountNo = accountNumbers.get(i % accountNumbers.size());
                String[] transaction = {
                        "TX" + System.currentTimeMillis() + ThreadLocalRandom.current().nextInt(1000, 9999),
                        accountNo,
                        transCodes[i % transCodes.length],
                        String.format("%.2f", faker.number().randomDouble(2, 10, 50000)),
                        faker.money().currencyCode(),
                        getRandomAccount(accountNumbers),
                        faker.timeAndDate().past(30, TimeUnit.DAYS, Config.DATE_TIME_FORMAT),
                        faker.options().option("成功", "失败"),
                        faker.options().option("ATM", "网银", "手机银行"),
                        DT
                };
                writer.write(String.join(",", transaction) + "\n");

                if (i % BATCH_SIZE == 0) writer.flush();
            }
        }
    }

    // 生成交易日志表
    private static void generateLogData() throws Exception {
        try (BufferedWriter writer = Files.newBufferedWriter(Paths.get(Config.CSV_PATH+"transaction_log.csv"))) {
            writer.write("log_id,transaction_id,log_level,log_message,log_time,dt\n");

            for (int i = 0; i < TOTAL_RECORDS; i++) {
                String[] log = {
                        "LOG" + System.nanoTime() + ThreadLocalRandom.current().nextInt(1000, 9999),
                        "TX" + System.currentTimeMillis() + ThreadLocalRandom.current().nextInt(1000, 9999),
                        faker.options().option("INFO", "ERROR"),
                        "{ \"errorCode\": \"" + faker.number().digits(3) + "\", \"message\": \"" + faker.lorem().sentence() + "\" }",
                        faker.timeAndDate().past(30, TimeUnit.DAYS, Config.DATE_TIME_FORMAT),
                        DT
                };
                writer.write(String.join(",", log) + "\n");

                if (i % BATCH_SIZE == 0) writer.flush();
            }
        }
    }

    // 辅助方法：生成有效身份证号
    private static String generateValidIdCard() {
        return faker.idNumber().ssnValid();
    }

    // 辅助方法：格式化日期
    private static String formatDate(Date date) {
        return DATE_FORMAT.format(date.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate());
    }

    // 辅助方法：格式化时间
    private static String formatTime(Date date) {
        return TIMESTAMP_FORMAT.format(date.toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime());
    }

    // 辅助方法：随机获取对手账户
    private static String getRandomAccount(List<String> accounts) {
        return accounts.get(ThreadLocalRandom.current().nextInt(accounts.size()));
    }
}